<template>
  <div class="ApplicationEditor" @wheel.ctrl.prevent.stop @contextmenu.prevent>
    <ApplicationEditorHeader></ApplicationEditorHeader>
    <div class="body">
      <!-- <ApplicationEditorSidebar class="sidebar"></ApplicationEditorSidebar> -->
      <div class="main-view">
        <DragLayoutContext :layoutNode="layoutRootNode">
          <ObjectEditorTabs
            name="main"
            ref="objectEditorTabs"
            @change="handelObjectEditorTabsChange"
          ></ObjectEditorTabs>
          <FileExplorer name="file-explorer"/>
          <Hierarchy name="hierarchy"/>
          <WidgetDefinition name="widget-definition"/>
          <Properties name="properties"/>
          <div name="test-4">test-4</div>
          <div name="test-5">test-5</div>
        </DragLayoutContext>
      </div>
    </div>
    <ApplicationEditorMenu ref="menu"></ApplicationEditorMenu>
  </div>
</template>
<script lang="ts">
import { VueConstructor } from 'vue/types/vue'
import { Component, Provide, Ref, Watch, Mixins } from 'vue-property-decorator'
import { LayoutNode } from '@/components/common/drag-layout/DragLayoutInterface'
import { JsonConvert } from '@/core/json2typescript/json-convert'
import EditableObject from '@/core/editable-object/EditableObject'
import defaultLayout from './default-layout'
import WidgetDefinitionMixins from './WidgetDefinitionMixins'

import ApplicationEditorHeader from './ApplicationEditorHeader.vue'
import DragLayoutContext from '@/components/common/drag-layout/DragLayoutContext.vue'
import ObjectEditorTabs from './object-editor-tabs/ObjectEditorTabs.vue'
import FileExplorer from './view/file-explorer/FileExplorer.vue'
import Hierarchy from './view/object-hierarchy/Hierarchy.vue'
import Properties from './view/properties-config/Properties.vue'
import WidgetDefinition from './view/widget-definition/WidgetDefinition.vue'
import { default as ApplicationEditorMenu, MeunItem} from './ApplicationEditorMenu.vue'

import Project from '@/core/file-model/Project'
import Directory from '@/core/file-model/Directory'
import File from '@/core/file-model/File'

import localforage from 'localforage'
import throttle from 'lodash.throttle'
import FileEditableObject from '@/core/editable-object/file/FileEditableObject'
import SettingEditableObject from '@/core/editable-object/setting/SettingEditableObject'
import builtInWidgets from '@/components/application-editor/widget/builtInWidgets'

@Component({
  name: 'ApplicationEditor',
  components: {
    ApplicationEditorHeader,
    DragLayoutContext,
    ObjectEditorTabs,
    Properties,
    WidgetDefinition,
    Hierarchy,
    FileExplorer,
    ApplicationEditorMenu
  }
})
export default class ApplicationEditor extends Mixins(WidgetDefinitionMixins) {
  @Ref()
  public objectEditorTabs!: ObjectEditorTabs

  @Ref()
  public menu!: ApplicationEditorMenu

  @Provide('app-editor')
  public get appEditor (): ApplicationEditor { return this }

  public project: Project = new Project()

  /** 当前激活的对象编辑器的KEY */
  public currentEditableObject: EditableObject| null = null

  private layoutRootNode: LayoutNode = defaultLayout

  public get projectFiles() {
    const projectFiles: File[] = []
    const  traverse = (directory: Directory) => {
      if (directory) {
        for (const subDirectory of directory.directorys) {
          traverse(subDirectory)
        }
        for (const file of directory.files) {
          projectFiles.push(file)
        }
      }
    }
    if (this.project) {
      traverse(this.project.rootDirectory)
    }
    return projectFiles
  }

  public get fileEditableObjectMap() {
    const map = new Map<File, FileEditableObject>()
    
    const  traverse = (directory: Directory, parentPath: string, parentDirectorys: Directory[]) => {
      if (directory) {
        for (const subDirectory of directory.directorys) {
          traverse(
            subDirectory,
            parentPath ? parentPath + '\\' + subDirectory.name : subDirectory.name,
            [...parentDirectorys, directory]
          )
        }
        for (const file of directory.files) {
          map.set(file, new FileEditableObject({
            propsData: {file, parentPath, appEditor: this, parentDirectorys: [...parentDirectorys, directory]}
          }))
        }
      }
    }

    if (this.project) {
      traverse(this.project.rootDirectory, '', [])
    }

    return map
  }

  public get fileEditableObjects () {
    const fileEditableObjects: FileEditableObject[] = []
    this.fileEditableObjectMap.forEach((d) => {
      fileEditableObjects.push(d)
    })
    return fileEditableObjects
  }
  
  public get settingEditableObject() {
    return new SettingEditableObject({propsData: {
      appEditor: this
    }})
  }

  public openObjectEditor(
    object: EditableObject,
    editor?: VueConstructor | undefined | null,
    isPreview = false
  ) {
    return this.objectEditorTabs.openObjectEditor(object, editor, isPreview)
  }

  public openSettingEditor() {
    this.openObjectEditor(this.settingEditableObject)
  }

  public openProject(project: Project) {
    this.project = project
    localforage.setItem('mani-project', this.project)
  }

  public openContextmenu(event: MouseEvent, meunItems: MeunItem[]) {
    this.menu.openContextmenu(event, meunItems)
  }

  @Watch('project', { deep: true })
  private projectChange(project: Project) {
    this.saveChange(project)
  }

  private saveChange = throttle((project) => {
    this.project && localforage.setItem('mani-project', project)
  }, 100)

  /* 事件处理 */
  private handelObjectEditorTabsChange(object: EditableObject| null) {
    this.currentEditableObject = object
  }

  @Watch('fileEditableObjects')
  private fileEditableObjectsChange () {
    const find = this.fileEditableObjects.find(d => d.displayName === 'App.vue')
    if (find) {
      this.appEditor.openObjectEditor(find)
    }
  }

  protected async mounted () {
    this.registerWidgetGroup('text', '文本')
    this.registerWidgetGroup('graph', '图形')

    builtInWidgets.forEach((options) => {
      this.registerWidget(options)
    })

    // const projectPlainObject = await localforage.getItem('mani-project')

    // console.log(JSON.stringify(projectPlainObject))

    // // if (projectPlainObject) {
    // //   this.project = new JsonConvert().deserializeObject(projectPlainObject, Project)
    // //   await this.$nextTick()
    // //   const find = this.fileEditableObjects.find(d => d.displayName === 'App.vue')
    // //   if (find) {
    // //     this.appEditor.openObjectEditor(find)
    // //   }
    // // }
  }
}
</script>
<style scoped lang="scss">
@import '~@/style/variables.scss';

$interval: 0px;

.ApplicationEditor {
  color: $text-color;
  font-size: 12px;
  background: $background-color;

  .body {
    display: flex;
    margin-top: 0px;
    width: 100%;
    height: calc(100% - #{$header-height + 1px});
    border-top: solid 1px $border-color;
    padding: $interval;
  }

  .sidebar {
    width: 175px;
    flex-shrink: 0;
    margin-right: $interval;
    border-right: solid 1px $border-color;
  }
 
  .main-view {
    flex-grow: 1;
    overflow: hidden;
  }
}
</style>

<style lang="scss">
@import '~@/style/global.scss';
</style>
